package com.star.learn.excel.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.star.learn.excel.component.ConfirmHolder;
import com.star.learn.excel.config.RabbitMQConfig;
import com.star.learn.excel.dto.BatchMessage;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;

import java.nio.charset.StandardCharsets;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class RabbitMQProducerService {

    @Resource
    private RabbitTemplate rabbitTemplate;

    // 注入 ConfirmHolder
    @Resource
    private ConfirmHolder confirmHolder;

    @PostConstruct
    public void init() {
        // 消息发送确认回调
        rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
            if (correlationData != null) {
                confirmHolder.notifyConfirm(correlationData.getId(), ack);
            }
            if (ack) {
                log.debug("MQ消息发送到交换机成功. CorrelationId: {}", correlationData != null ? correlationData.getId() : "N/A");
            } else {
                log.error("MQ消息发送到交换机失败. CorrelationId: {}, 原因: {}", correlationData != null ? correlationData.getId() : "N/A", cause);
            }
        });

        // 消息不可达回退（无队列接收）
        rabbitTemplate.setReturnsCallback(returned -> {
            String messageBody = new String(returned.getMessage().getBody(), StandardCharsets.UTF_8);
            log.error("MQ消息无法路由到队列. Exchange: {}, Routing Key: {}, Reply Code: {}, Reply Text: {}, Message: {}",
                    returned.getExchange(), returned.getRoutingKey(), returned.getReplyCode(), returned.getReplyText(), messageBody);
        });
    }

    /**
     * 发送实际数据批次到主队列，并等待确认
     */
    public boolean sendAndConfirm(String fileId, String sheetName, int batchNum, int batchSize) {
        String correlationId = UUID.randomUUID().toString();
        try {
            // 创建 DTO 对象
            BatchMessage batchMessage = new BatchMessage(fileId, sheetName, batchNum, batchSize);
            // 使用 ObjectMapper 序列化
            ObjectMapper mapper = new ObjectMapper();
            String msgBody = mapper.writeValueAsString(batchMessage);

            MessageProperties props = new MessageProperties();
            props.setContentType("application/json");
            props.setDeliveryMode(MessageDeliveryMode.PERSISTENT);
            props.setHeader("fileId", fileId);
            props.setHeader("sheetName", sheetName);
            props.setHeader("batchNum", batchNum);
            props.setHeader("batchSize", batchSize);

            Message message = new Message(msgBody.getBytes(StandardCharsets.UTF_8), props);

            CorrelationData correlationData = new CorrelationData(correlationId);

            CompletableFuture<Boolean> future = new CompletableFuture<>();
            confirmHolder.register(correlationId, future);

            rabbitTemplate.send(RabbitMQConfig.EXCHANGE, RabbitMQConfig.ROUTING_KEY, message, correlationData);

            log.debug("MQ触发消息发送中... FileId: {}, Sheet: {}, Batch: {}, CorrelationId: {}",
                    fileId, sheetName, batchNum, correlationId);

            // 等待确认，最多 5 秒
            boolean confirmed = future.get(5, TimeUnit.SECONDS);
            if (!confirmed) {
                log.warn("MQ触发消息发送到交换机但未确认. FileId: {}, Sheet: {}, Batch: {}, CorrelationId: {}",
                        fileId, sheetName, batchNum, correlationId);
            }
            return confirmed;

        } catch (Exception e) {
            // 异常发生，确保 future 被 complete 或取消
            confirmHolder.notifyConfirm(correlationId, false);
            log.error("MQ触发消息发送异常. FileId: {}, Sheet: {}, Batch: {}, CorrelationId: {}",
                    fileId, sheetName, batchNum, correlationId, e);
            // 异常发生时返回 false，ExcelUtil 根据此结果判断是否成功
            return false;
        }
    }
}
